Skip to content

Native GPU fixed-step path (Phase B): OpenACC integration without runtime CoreNEURON - #3801

Draft
nrnhines wants to merge 51 commits into
masterfrom
hines-grok/feature/neuron-core-gpu-adoption
Draft

Native GPU fixed-step path (Phase B): OpenACC integration without runtime CoreNEURON#3801
nrnhines wants to merge 51 commits into
masterfrom
hines-grok/feature/neuron-core-gpu-adoption

Conversation

@nrnhines

Copy link
Copy Markdown
Member

Summary

Introduces NEURON's native GPU backend (gpu.backend="native") for fixed-step
pc.psolve / h.fadvance using NVHPC + OpenACC. Models can run on the GPU
without enabling CoreNEURON at runtime (coreneuron.enable=False).

Phase B delivers CoreNEURON-parity integration for single-process modtests while
keeping cross-rank spike scheduling on the CPU (same split CoreNEURON uses).

from neuron import h, gpu

pc = h.ParallelContext()
gpu.enable = True
gpu.backend = "native"
pc.psolve(100)

What's in scopeFixed-step native GPU timestep: matrix solve, mechanism integration, post-solveOpenACC solve_interleaved when node order is permutedDevice upload lifecycle (device_token), padded Memb_list shellsNET_RECEIVE on GPU; net_send GPU buffer; CPU spike queues + MPIGap junctions with device voltage sync before MPIBatch download API (download_flush_interval) for Vector.record / graphsNMODL NEURON OpenACC codegen visitorPython GPU API (neuron.gpu) and ParallelContext GPU methods19/19 *_py_gpu_native modtests (parity with single-process *_py_gpu)
• Sphinx scope contract: docs/dev/native-gpu-fixed-step.rstDevelopment journal: docs/dev/native-gpu-adoption/

Explicit boundaries (not in this PR)

• CVode / IDA on native GPU (error if CVode active with native GPU enabled)
• GPU spike priority queueFull multi-thread OpenACC maturity (pc.nthread(1) is the validated default)
• GPU sparse13 / DAE (extracellular, LinearMechanism) — host fallbackStandalone -DNRN_ENABLE_GPU=ON configure without -DNRN_ENABLE_CORENEURON=ONMPI-native modtest expansion beyond the current parity set

See docs/dev/native-gpu-adoption/04-known-limitations.md for details.

Build requirementsNVHPC (tested with 25.9) + CUDA-capable GPU-DNRN_ENABLE_GPU=ON -DNRN_GPU_BACKEND=OpenACC-DNRN_ENABLE_CORENEURON=ON (configure-time requirement; runtime CoreNEURON not required)

CPU-only builds (NRN_ENABLE_GPU=OFF) remain supported.

Testing

ctest --output-on-failure -R '_py_gpu_native'
ctest --output-on-failure -R testneuron_gpu
ctest --output-on-failure -R gpu

NVHPC GPU build verified locally on ThinkStation P5 (CUDA arch 75).

DocumentationUser/scope contract: docs/dev/native-gpu-fixed-step.rstDeveloper journal: docs/dev/native-gpu-adoption/ (design decisions, L0L8 map, test parity, Phase B closure checklist)
• GPU testing / CI notes: docs/dev/gpu-testing.rst

Review notes

This is a large adoption branch (~100 files). Suggested review lenses:

1. Runtime contractfadvance dispatch, neuron::gpu::*, treeset.cpp OpenACC matrix setup
2. Device lifecycleupload/invalidate, NrnThread GPU fields, sync boundaries
3. Network eventsspike policy (CPU queues), NetSendBuffer, gap/VecPlay sync
4. Tests_py_gpu_native parity, unit tests under test/unit_tests/gpu/
5. DocsSphinx scope matches actual behavior and known limitations

Related

Closes Phase B of the native GPU adoption plan. Follow-up work (CVode-on-GPU, standalone GPU configure, MPI-native modtests, etc.) is tracked in docs/dev/native-gpu-adoption/05-future-work.md.

nrnhines and others added 30 commits June 8, 2026 08:52
- Support both 'main' and 'master' as base branch
- Only pass existing files to the formatter
- Eliminates noisy "ERROR: X jobs failed" when files were deleted
…ep 1)

Introduce user-facing NEURON native GPU build options as scaffolding
for the GPU adoption plan. During Phase A, NRN_ENABLE_GPU still requires
CoreNEURON; CORENRN_ENABLE_GPU remains required for actual GPU execution.

- Add NRN_ENABLE_GPU (OFF default) and NRN_GPU_BACKEND=OpenACC
- Extend NeuronTestHelper REQUIRES gpu to accept NRN_ENABLE_GPU
- Document options in cmake_doc/options.rst and dev/gpu-testing.rst

Implemented by Grok (AI assistant).
Align the typical GPU development build example with gpu_workstation.md:
add CMAKE_CUDA_COMPILER, install prefix, and CMAKE_CUDA_ARCHITECTURES.
Clarify that the arch flag is optional (CoreNEURON defaults to 70;80)
but recommended for single-GPU dev machines.

Implemented by Grok (AI assistant).
external_ringtest::coreneuron_gpu_mpi failed on some NVHPC builds when
NEURON special was launched with -coreneuron -gpu under MPI
(pgcudafat*.o: cannot open shared object file).

- Run GPU MPI ringtest via special-core (dump with special, simulate
  with special-core --gpu); copy out.dat to spk2.std for group comparison
- Set per-test TMPDIR under the build tree for all REQUIRES gpu ctests
- Apply -cuda/OpenACC link flags to NEURON libnrnmech/special in
  neuronMechMaker when CORENRN_ENABLE_GPU (mirror corenrnmech treatment)
- Document the ringtest ctest behavior in docs/dev/gpu-testing.rst

Implemented by Grok (AI assistant).
Apply NVHPC OpenACC compile flags to cellorder sources in libnrniv,
link coreneuron-cuda for the interleaved-solve CUDA launcher, and add
compile-only cellorder_openacc_smoke CI guard. Guard NEURON builds of
cellorder.cpp so corenrn_param and NrnThread GPU fields remain PR 5/7
work. Extend neuronMechMaker and test LD_LIBRARY_PATH for NVHPC/CUDA
dynamic loading after libnrniv gains OpenACC fat objects.

Implemented by Grok (AI assistant).
Fork CoreNEURON offload helpers into src/neuron/gpu/offload.hpp with
neuron::gpu::target_* APIs and nrn_target_* macros. Add offload.cpp
(debug logging via NRN_GPU_DEBUG, NVHPC present-table workaround) as
neuron_gpu static library linked into libnrniv. Add standalone
testneuron_gpu_offload unit test for copyin/deviceptr/delete round trip.

Implemented by Grok (AI assistant).
Add neuron::gpu::device_token with refcounted ModelDeviceState tied to
model_sorted_token lifetime, ensure_on_device() upload stub, and
invalidate_device_state() on layout invalidation. Extend NrnThread with
compute_gpu and stream_id for upcoming OpenACC clauses (PR 7).

Implemented by Grok (AI assistant).
Wire create_nrnmech and the nrnivmodl CMake wrapper to default NMODL
NEURON codegen when NRN_ENABLE_GPU=ON, reject forced NOCMODL on GPU
builds, and document NMODL-vs-NOCMODL feature gaps. Shell nrnivmodl
keeps NOCMODL during Phase A so existing GPU ctests remain green.

Implemented by Grok (AI assistant).
Add neuron::gpu::config (enabled/use_cuda_launcher stubs), refactor
cellorder matrix access to host-resolved raw pointers for OpenACC
device-link compatibility, and keep CoreNEURON OpenACC/CUDA launcher paths
unchanged. NEURON native OpenACC offload on libnrniv is deferred to PR 9
(SOA upload) to avoid NVHPC pgcudafat loader regressions with special.

Implemented by Grok (AI assistant).
Add CodegenNeuronAccVisitor for native GPU mechanism codegen: OpenACC
parallel loops and present clauses on nrn_init/nrn_state/nrn_cur entrypoints,
wired via `nmodl --neuron acc --oacc`. Default NMODL_NEURON_EXTRA_ARGS on GPU
builds appends acc --oacc. Prototype gate: hh.mod unit test checks
nrn_pragma_acc emission.

Implemented by Grok (AI assistant).
New GPU adoption sources follow the no-header style used in src/neuron/gpu/;
ensure trailing newlines on codegen_neuron_acc_visitor files.

Implemented by Grok (AI assistant).
Replace device_token upload stubs with real OpenACC copyin for sorted node
and mechanism SOA vectors, plus CoreNEURON-style struct-then-patch upload
for InterleaveInfo permute types 1 and 2. Compile upload.cpp as a dedicated
neuron_gpu_upload object library linked into libnrniv and GPU unit tests.

Implemented by Grok (AI assistant).
Add gpu.enable/gpu.backend runtime config with hoc helpers and
share/lib/python/neuron/gpu.py. Dispatch nrn_fixed_step_thread to
neuron::gpu::fixed_step_thread when native backend is active; fused
lastpart for the no-gap case mirrors CoreNEURON fadvance_core layout.
Unit test gpu_fadvance covers config gate and dispatch counter.

Implemented by Grok (AI assistant).
Add neuron::gpu net_events wrappers for deliver_net_events,
nrn_deliver_events, and native-gated spike_exchange_after_group.
Wire deliver_net_events_host into fixed_step_thread and call
spike_exchange_after_group from nrn_fixed_step_group. Unit tests
gpu_net_events and gpu_fadvance cover wrappers and dispatch.

Implemented by Grok (AI assistant).
Route post-step delivery through deliver_post_step_events_host when native
GPU is active. Add backend_helper and G4 native ctests (pointer, psolve,
spikes, watchrange, nmodlrandom) launched via special with
NRN_GPU_BACKEND_TEST=native. Extend NeuronTestHelper TMPDIR guard for
NRN_ENABLE_GPU; install share/lib/python/neuron/gpu.py.

Implemented by Grok (AI assistant).
Add -gpu-native flag (tracked patch for external/tests/ringtest clone),
external_ringtest::neuron_gpu_native_mpi ctest with TMPDIR wrapper, and
docs for runtime/spike reporting and sortspike workflow.

Implemented by Grok (AI assistant).
Port CoreNEURON init_gpu() policy to neuron::gpu::assign_device()
(local_rank % num_gpus_per_node) with gpu.device_count runtime config.
Add OpenACC device helpers, ParallelContext gpu_assign_device/gpu_device_id,
unit tests, and a 2-rank MPI smoke test.

Implemented by Grok (AI assistant).
Move runtime GPU config to ParallelContext methods (gpu_enable,
gpu_backend, gpu_device_count) and expand neuron.gpu with device_count,
permute, and context manager. Add coreneuron deprecation shims, extend
_check_for_intel_openmp() for NRN_ENABLE_GPU builds, and document the
configuration truth table.

Implemented by Grok (AI assistant).
…er copies)

- Compare neuron_gpu_native_mpi against spk2.std (MPI ringtest output).
- Copy backend_helper.py into coreneuron_modtests and standalone psolve trees.

Implemented by Grok (AI assistant).
Port CoreNEURON-style OpenACC loops for SoA rhs/d zeroing and axial
current assembly in nrn_rhs/nrn_lhs, gated on NrnThread::compute_gpu.
Compile treeset.cpp with NVHPC OpenACC flags via libnrniv.

Implemented by Grok (AI assistant).
PR 11b: NetSendBuffer_t on Memb_list, hoc_register_net_send_buffering,
codegen_neuron_acc net_send_buffering/delivery, flush after setup_tree_matrix.

PR 16: sync_before/after_vecplay and gap voltage host sync; native
fadvance_gpu runs MPI gap transfer + lastpart when partrans is active.

Implemented by Grok (AI assistant).
Upload per-thread _v_parent_index in upload_sorted_model so OpenACC
present(parent_i) in treeset.cpp succeeds on device.

Apply node-order permute immediately via verify_structure() when
gpu.enable triggers optimize_node_order after finitialize, fixing
testcorenrn_*::coreneuron_gpu_online model_ready() errors.

Add host/device matrix sync for the hybrid native GPU path: mechanisms
run on host while axial setup uses OpenACC. Zero rhs/d on host, push
mechanism updates to device before axial loops, pull back before
nonvint blocks and host solve, then push voltages after update.

Skip test_watchrange2 under CORENRN_ENABLE_GPU (cvode threading vs
in-process GPU permute).

ctest -R gpu: 80/82 pass (was 67/82). Remaining: test_pointer_py_gpu
and test_pointer_py_gpu_native (fast_imem vs axial.im under GPU).
The hybrid native GPU step was corrupting host matrix state after
setup_tree_matrix: a redundant device→host pull ran after nonvint had
already updated vec_rhs/vec_d on the host, so the Hines solve and
nrn_calc_fast_imem saw stale RHS data (im != i_membrane_).

Also fix voltage sync ordering: stop clobbering host voltages with a
pre-vecplay device→host pull, and push host voltages to the device after
lastpart so the next step starts from consistent state.

Matrix assembly/solve/fast_imem remain on the host in this hybrid path;
OpenACC axial can be re-enabled once its device mirrors are validated.

ctest -R gpu: 82/82 pass (including test_pointer_py_gpu and _native).
…path

Re-enable OpenACC axial loops in setup_tree_matrix and GPU Hines solve
with minimal per-step host traffic:

- Push post-nonvint vec_rhs/vec_d to device before solve; pull only vec_rhs
  back afterward for host voltage update and fast_imem.
- Upload NrnThread shells (parent index pointer patched) so solve_interleaved
  present(nt) works under NRN_ENABLE_GPU without CORENRN_BUILD.
- Enable OpenACC solve branches in cellorder.cpp for NEURON native builds.
- Fix lhs device sync clobbering rhs axial results: use diagonal-only
  vec_d/sav_d sync in nrn_lhs; add OpenACC waits after async axial loops.
- Sync voltages to device immediately before rhs axial.

Per-step host work remains mechanisms, nonvint, second_order_cur, and
nrn_update_voltage/fast_imem (CVode still deferred).

ctest -R gpu: 82/82 pass.
Move second-order ion correction, voltage increment, capacitance
current, and fast_imem off the per-step vec_rhs host pull. The native
GPU step now keeps the Hines solution on device and syncs only node
voltages and fast_imem sav_rhs for HOC/VecPlay reads.

Upload mechanism nodeindices so OpenACC post-solve kernels can index
into the sorted matrix. Host fallbacks remain for sparse13,
extracellular, and LFP hooks.

ctest -R gpu: 82/82 pass.
Mirror CoreNEURON-style mechanism device setup for NEURON native OpenACC:
copy Memb_list shells, patch nodeindices/_thread/pdata/net_send_buffer
pointers, upload SoA-padded pdata rows, and refresh per-thread _ml_list
arrays on the device. Add _nodecount_padded on Memb_list for GPU kernels.

Mechanism currents still run on the host in this step; the upload removes
partial-present OpenACC hazards for NMODL GPU codegen and net_send buffers.

ctest -R gpu: 82/82 pass.
Introduce download_flush_interval (default 1, 0 = psolve end only) to
defer host pulls of voltages and fast_imem sav_rhs during native GPU
psolve. device_token::update_host/update_device now perform selective
batch download/upload; Graph.flush triggers download for live plots.

Hook finalize_psolve_download at fixed-step and step-group completion so
HOC reads after psolve stay correct when interval is 0.

ctest -R gpu: 82/82 pass.
Add 14 native GPU modtests mirroring single-process CoreNEURON _py_gpu
coverage: fornetcon, direct, spikes variants, fast_imem, datareturn,
units, netmove, pointer, watchrange, psolve, ba, nmodlrandom, natrans,
and array_variable_transfer run modes.

Route modtests through backend_helper for both native and CoreNEURON
paths, copy the helper into all affected CTest working directories, and
fix native-only issues (sys.path, set_maxstep, single-thread datareturn).

Serialize ensure_on_device upload under the device-state mutex to prevent
concurrent UploadState corruption when multiple NEURON threads first enter
the GPU path (fixes test_natrans double-free).
nrnhines added 4 commits June 21, 2026 19:12
…rok/feature/neuron-core-gpu-adoption

Want to pass ci formatting when this becomes a pull request.
treeset.cpp: include neuron/gpu/offload.hpp unconditionally so nrn_pragma_acc
macros are no-op stubs without GPU/OpenACC.

nrnivmodl.in: prefix every line of GPU-only nocmodl guards (not just the if).

gpu.py: skip _sync_to_hoc when HOC gpu_* methods are absent (non-GPU builds).

test_fast_imem.py: import backend_helper only when backend tests will run;
ship backend_helper.py with basic_tests SCRIPT_PATTERNS.
Remove unused sync_voltage_and_rhs_to_device helper, mark
solve_interleaved2_loop_body as routine gang so inner loop vector
directives are valid under the outer gang parallel region, and use
the nodiscard ensure_on_device return value in the device_state test.
@nrnhines
nrnhines marked this pull request as draft June 22, 2026 14:55
@azure-pipelines

Copy link
Copy Markdown

✔️ 35f0822 -> Azure artifacts URL

@github-actions

Copy link
Copy Markdown
Contributor

✔️ 35f0822 -> artifacts URL

@nrnhines nrnhines added documentation nmodl gpu performance Issue or PR related to performance labels Jun 22, 2026
…egen

NMODL NEURON C++ codegen registers net_send/net_event mechanisms via
hoc_register_net_send_buffering, but the symbol lived only in the GPU
object library. Provide a CPU no-op stub and expose the declaration in
mech_api.h/nrniv_mf.h so nrnivmodl-generated mechanisms compile when
NRN_ENABLE_GPU=OFF.
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.65306% with 67 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.33%. Comparing base (2ac5cc7) to head (9874a5b).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
share/lib/python/neuron/gpu.py 54.80% 47 Missing ⚠️
src/nrnoc/treeset.cpp 58.06% 13 Missing ⚠️
share/lib/python/neuron/coreneuron.py 75.00% 5 Missing ⚠️
share/lib/python/neuron/__init__.py 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3801      +/-   ##
==========================================
- Coverage   68.45%   68.33%   -0.12%     
==========================================
  Files         688      690       +2     
  Lines      111300   111514     +214     
==========================================
+ Hits        76187    76207      +20     
- Misses      35113    35307     +194     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

✔️ a34dc84 -> artifacts URL

@azure-pipelines

Copy link
Copy Markdown

✔️ a34dc84 -> Azure artifacts URL

Turn on the Phase B native GPU CMake options (OpenACC, CUDA arch 75) on
the self-hosted NVHPC runner and run the focused CTest subset from
docs/dev/gpu-testing.rst instead of the full suite.
@azure-pipelines

Copy link
Copy Markdown

✔️ fc81dcb -> Azure artifacts URL

@github-actions

Copy link
Copy Markdown
Contributor

✔️ fc81dcb -> artifacts URL

@nrnhines
nrnhines marked this pull request as ready for review June 23, 2026 01:16
@azure-pipelines

Copy link
Copy Markdown

✔️ fc81dcb -> Azure artifacts URL

routine gang inside a parallel loop gang is NVC++-S-1045. Revert the
35f0822 gang annotation to seq so cellorder.cpp compiles on NVHPC 25.9;
inner loop vector directives remain inside the seq routine.
@azure-pipelines

Copy link
Copy Markdown

✔️ 4053d97 -> Azure artifacts URL

@github-actions

Copy link
Copy Markdown
Contributor

✔️ 4053d97 -> artifacts URL

Grok and others added 3 commits June 24, 2026 18:10
Native GPU fixed-step integration diverges with the default
interleave_permute_type=0 (non-interleaved nrn_solve on device). HOC callers
that set pc.gpu_enable(1) and pc.gpu_backend("native") without
pc.optimize_node_order(2) therefore produced wrong spike rasters on large
models such as Traub 82894.

Mirror the Python gpu.enable path (which already applies permute 2) and
CoreNEURON's GPU guard: when gpu.enable and gpu.backend="native" are both
active, call nrn_optimize_node_order(2) if permute is not already 2.
Trigger from set_enable(true) and set_backend() so ordering of the two HOC
calls does not matter.

Add unit test with a stub nrn_optimize_node_order verifying permute 0 and 1
are upgraded to 2.
Gap/partrans models register nrnthread_vi_compute_, forcing host post-solve.
The hybrid GPU solve plus device→host sync_gap_after_voltage_update was
pulling stale device voltages over the host nrn_update_voltage result (0
spikes on nrntraub with use_gap=1). Add sync_gap_after_host_voltage_update
to push host voltages to device when post-solve ran on the host.

Full hybrid stepping still diverged on Traub; until device gap gather/scatter
is complete, dispatch the CPU fixed-step body when nrnthread_v_transfer_ is
registered so native GPU enable_gpu models with gaps match CPU rasters.

Add test/gjtests/test_par_gj_native_gpu.py comparing ggap voltages CPU vs
native GPU.
Phase B docs previously described a hybrid GPU solve with host partrans
gather/scatter. When nrnthread_v_transfer_ is registered, fadvance.cpp
dispatches the full CPU fixed-step body instead of fadvance_gpu.cpp.

Update the Sphinx scope contract, design journal, limitations, future work,
test parity notes, and Phase B checklist to match.
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

✔️ 9874a5b -> artifacts URL

@azure-pipelines

Copy link
Copy Markdown

✔️ 9874a5b -> Azure artifacts URL

@nrnhines
nrnhines marked this pull request as draft July 6, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation gpu nmodl performance Issue or PR related to performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants